package main

/*
* Content: Go 实现协程池控制高并发
* --------------------------------------------------
* goroutine work pool, 可以防止goroutine暴涨或者泄露: https://juejin.cn/post/6943952470993272845
 */

import (
	"fmt"
	"time"
)

// 原理: 同时启动几个 协程 共同完成 某项任务(任务就是通过 有缓冲的channel 进行传递的), 即线程池
//		 协程池里的协程实现了完成 某项任务 的 具体逻辑

// 使用 work pool 防止goroutine的 泄露 和 暴涨
func workerInPool(id int, jobs <-chan int, results chan<- int) {

	// jobs 中即使为空, for 循环也不会而退出, 除非关闭 jobs (jobs 关闭之后才会退出 for 循环)
	// 但是如果程序执行结束时 jobs 也没有关闭, 也会直接退出
	for j := range jobs {
		fmt.Printf("worker:%d start job:%d\n", id, j)
		time.Sleep(time.Second)
		fmt.Printf("worker:%d end job:%d\n", id, j)
		results <- j * 2
	}

}

func MyGroutinePool() {

	// Go 实现协程池控制高并发
	fmt.Println("--------------------Go 实现协程池 控制高并发--------------------")

	jobs := make(chan int, 100)
	results := make(chan int, 100)

	// 开启5个 goroutine: 这是线程池 (包含3个线程的线程池, 3个线程 同时运行, 从 jobs 中取出任务并进行处理)
	for w := 1; w <= 5; w++ {
		go workerInPool(w, jobs, results)
	}

	// 100个任务 (往 jobs 中添加任务, work pool 中的 3 个协程一起从 jobs 中取出数据)
	for j := 1; j <= 100; j++ {
		jobs <- j
	}

	time.Sleep(time.Second * 10) // 设置延迟, 晚一点关闭 jobs, 让子弹飞一会
	close(jobs)                  // 关闭jobs, worker里的 for循环 将会退出

	// 输出结果
	for a := 1; a <= 5; a++ {
		<-results
	}
}
